using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using NetTopologySuite.Triangulate;
using PointAsLine.NotUsed;

namespace PointAsLine
{
    public partial class Form1 : Form
    {
        private List<Point> points = new List<Point>(); // 存储用户点击的点
        private PictureBox pictureBox;

        private Pen m_linePen;
        private List<Pen> m_linePen2;
        private List<Brush> m_brushes;

        public Form1()
        {
            InitializeComponent();
            this.Text = "点绘制成线段拟合";
            this.Size = new Size(800, 600);

            // 初始化 PictureBox
            pictureBox = new PictureBox
            {
                BorderStyle = BorderStyle.FixedSingle
            };
            pictureBox.Size = new Size(512, 512);
            pictureBox.Paint += PictureBox_Paint;
            this.Controls.Add(pictureBox);

            // 绑定鼠标点击事件
            pictureBox.MouseClick += PictureBox_MouseClick;

            // 添加拟合按钮
            Button fitButton = new Button
            {
                Text = "拟合线段",
                Dock = DockStyle.Bottom,
                Height = 40
            };
            fitButton.Click += FitButton_Click2;
            this.Controls.Add(fitButton);

            m_linePen = new Pen(Brushes.Brown, 3);
            m_linePen2 = new List<Pen>{
                new Pen(Brushes.Green, 3),
                new Pen(Brushes.BlanchedAlmond, 3),
                new Pen(Brushes.Crimson, 3),
                new Pen(Brushes.DarkBlue, 3),
              };
            m_brushes = new List<Brush>{
                Brushes.Green,
                Brushes.BlanchedAlmond,
                 Brushes.Crimson,
                Brushes.DarkBlue,
              };
        }

        private void PictureBox_Paint(object? sender, PaintEventArgs e)
        {
            var g = e.Graphics;
            g.Clear(Color.White);
            // 绘制所有点

            if (this.checkBox1.Checked)
            {
                foreach (Point p in points)
                {
                    g.FillEllipse(Brushes.Red, p.X - 3, p.Y - 3, 6, 6);
                }

                if (pointGroups != null)
                {
                    var t = this.comboBoxPointGroup.SelectedIndex;
                    if (t > 0)
                    {
                        for (var i = 0; i < pointGroups.Count; i++)
                        {
                            if (t > 0 && t != i + 1)
                            {
                                continue;
                            }
                            foreach (PointF2G p in pointGroups[i])
                            {
                                var b = m_brushes[i % m_brushes.Count];
                                if (t >= 1)
                                {
                                    b = Brushes.Blue;
                                }
                                g.FillEllipse(b, p.X - 3, p.Y - 3, 6, 6);
                            }
                            if (this.checkBoxPointGroup.Checked)
                                g.DrawString("g" + i, this.Font, Brushes.Blue, pointGroups[i][0].ToPointF());
                        }
                    }

                }
            }

            if (this.checkBox2.Checked)
            {
                var t = this.comboBox1.SelectedIndex;
                if (segments != null)
                {
                    int segIndex = -1;
                    for (var j = 0; j < segments.Count; j++)
                    {
                        if (t > 0 && t != j + 1)
                        {
                            continue;
                        }
                        segIndex++;
                        Polyline segment = segments[j];

                        for (int i = 0; i < segment.Count - 1; i++)
                        {
                            g.DrawLine(m_linePen2[segIndex % m_linePen2.Count], Point.Round(segment[i].ToPointF()), Point.Round(segment[i + 1].ToPointF()));
                        }
                        if (this.checkBoxShowRegNum.Checked)
                        {
                            g.DrawString(j + "0", this.Font, Brushes.Blue, segment[0].ToPointF());
                            g.DrawString(j + "n", this.Font, Brushes.Blue, segment[segment.Count - 1].ToPointF());
                        }
                    }
                }

            }

            if (this.checkBox3.Checked)
            {
                int segIndex = 0;
                var t = this.comboBox2.SelectedIndex;
                if (simplifiedSegments != null)
                {
                    foreach (Polyline segment in simplifiedSegments)
                    {
                        if (segment.Count < 2) continue;

                        if (t <= 0 || t == segIndex + 1)
                        {
                            for (int i = 0; i < segment.Count - 1; i++)
                            {
                                g.DrawLine(m_linePen2[segIndex % m_linePen2.Count], Point.Round(segment[i].ToPointF()), Point.Round(segment[i + 1].ToPointF()));
                            }

                            if (this.checkBoxShowSimpleLineNum.Checked)
                            {
                                g.DrawString(segIndex + "0", this.Font, Brushes.Red, segment[0].ToPointF());
                                g.DrawString(segIndex + "n", this.Font, Brushes.Red, segment[segment.Count - 1].ToPointF());
                            }
                        }

                        segIndex++;
                    }
                }
            }


            if (this.checkBoxRegPolygon.Checked)
            {
                int segIndex = 0;
                var t = this.comboBox2.SelectedIndex;
                if (polygonSegements != null)
                {
                    foreach (Polyline segment in polygonSegements)
                    {
                        if (segment.Count < 2) continue;

                        if (t <= 0 || t == segIndex + 1)
                        {
                            for (int i = 0; i < segment.Count - 1; i++)
                            {
                                g.DrawLine(m_linePen2[segIndex % m_linePen2.Count], Point.Round(segment[i].ToPointF()), Point.Round(segment[i + 1].ToPointF()));
                            }

                            if (this.checkBoxShowSimpleLineNum.Checked)
                            {
                                g.DrawString(segIndex + "0", this.Font, Brushes.Red, segment[0].ToPointF());
                                g.DrawString(segIndex + "n", this.Font, Brushes.Red, segment[segment.Count - 1].ToPointF());
                            }
                        }

                        segIndex++;
                    }
                }
            }

            g.Flush();
        }

        private void PictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            // 记录点击的点（注意坐标转换）
            Point clickedPoint = e.Location;
            points.Add(clickedPoint);

            // 刷新显示
            pictureBox.Refresh();
        }

        private void FitButton_Click2(object sender, EventArgs e)
        {
            if (points.Count < 2)
            {
                MessageBox.Show("至少需要两个点才能拟合线段。");
                return;
            }

            // 将 C# 的 Point 转换为 OpenCV 的 Point2f
            PointF[] pointsF = points.ConvertAll(p => new PointF(p.X, p.Y)).ToArray();

            // 使用最近邻连接法拟合线段
            var dis = (int)this.numericUpDown1.Value;

            pointGroups.Clear();
            pointGroups = GroupProcessor.GetGroups(pointsF, 8);
            BuildCombox(this.comboBoxPointGroup, pointGroups.Count);

            segments = NearestNeighborSegmentation.Segmentation(pointGroups, maxDistance: dis);

            BuildCombox(this.comboBox1, segments.Count);

            var simDis = (int)this.numericUpDown2.Value;

            simplifiedSegments.Clear();
            polygonSegements.Clear();

            // 在 Mat 上绘制拟合的线段
            if (this.checkBoxLineSimplifier.Checked)
            {
                foreach (Polyline segment in segments)
                {
                    if (segment.Count < 2) continue;
                    var s3 = LineSimplifier.SimplifySegments(segment, maxDistance: simDis);
                    simplifiedSegments.Add(s3);
                }
                for (var i = simplifiedSegments.Count - 1; i >= 0; i--)
                {
                    if (simplifiedSegments[i].Count == 0)
                    {
                        simplifiedSegments.RemoveAt(i);
                    }
                }
            }


            if (this.checkBoxCircleLineHandler.Checked)
            {
                CircleLineHandler.Threshold = 2;
                simplifiedSegments = CircleLineHandler.Process(simplifiedSegments);
            }


            if (this.checkBoxSegmentMerger.Checked)
            {
                var s2 = (float)numericUpDownSeg2.Value;
                simplifiedSegments = SegmentMerger.MergeSegments(simplifiedSegments, PointFFunc.MeterToPixel(s2));
            }

            if (this.checkBoxPolygonBuilder.Checked)
            {
                PolygonBuilder2 polygonBuilder2 = new PolygonBuilder2();
                polygonSegements = polygonBuilder2.BuildPolygonsFromSegmentsMain(simplifiedSegments, 5);
            }
            
            if (this.checkBoxConnectHeadTrailer.Checked)
            {
                simplifiedSegments = ConnectHeadTrailer.Connect(simplifiedSegments, PointFFunc.MeterToPixel(50));
            }


            if (this.checkBoxSelfIntersectingPolygonMerge.Checked)
            {
                simplifiedSegments = SelfIntersectingPolygonMerge.MergeSelfIntersectingPolygon(simplifiedSegments);
            }

            if (this.checkBoxRemoveLenthSmall.Checked)
            {
                simplifiedSegments = RemoveLenthSmall.Remove(simplifiedSegments, PointFFunc.MeterToPixel(50));
            }

            BuildCombox(this.comboBox2, simplifiedSegments.Count);


            ComputeSum();

            this.pictureBox.Refresh();
        }

        

        private void BuildCombox(System.Windows.Forms.ComboBox comboBox, int count)
        {
            comboBox.Items.Clear();
            comboBox.Items.Add("所有");
            for (var i = 0; i < count; i++)
            {
                comboBox.Items.Add(i.ToString());
            }
        }

        private List<List<PointF2G>> pointGroups = new List<List<PointF2G>>();
        private List<Polyline> segments = new List<Polyline>();
        private List<Polyline> simplifiedSegments = new List<Polyline>();
        private List<Polyline> polygonSegements=new List<Polyline>();


        private void ComputeSum()
        {
            var s1 = 0;
            foreach (var segment in segments)
            {
                s1 += segment.Count;
            }
            this.checkBox2.Text = "识别的线(" + s1 + ")";

            var s2 = 0;
            foreach (var segment2 in simplifiedSegments)
            {
                s2 += segment2.Count;
            }
            this.checkBox3.Text = "简化线(" + s2 + ")";
        }



        private void 打开ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // 创建打开文件对话框
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*";
                openFileDialog.Title = "选择点数据文件";

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    // 调用readTxt方法读取选中的文件
                    readTxt(openFileDialog.FileName);
                }
            }
        }

        private void readTxt(string path)
        {
            // 清空当前点集
            points.Clear();
            pointGroups.Clear();
            segments.Clear();
            simplifiedSegments.Clear();

            try
            {
                // 读取文件的所有行
                string[] lines = System.IO.File.ReadAllLines(path);

                // 用于存储原始坐标，以便计算缩放和偏移
                List<PointWithColor> originalPoints = new List<PointWithColor>();

                foreach (string line in lines)
                {
                    // 分割每行的数据
                    string[] parts = line.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                    // 确保至少有3个部分（X, Y, Z坐标）
                    if (parts.Length >= 3)
                    {
                        // 尝试解析X和Y坐标（忽略Z坐标和颜色值）
                        if (double.TryParse(parts[0], out double x) && double.TryParse(parts[1], out double y))
                        {
                            // 将原始坐标添加到列表中
                            var colorR = int.Parse(parts[3]);
                            var colorG = int.Parse(parts[4]);
                            var colorB = int.Parse(parts[5]);
                            originalPoints.Add(item: new PointWithColor((float)x, (float)y, 0, colorR, colorB, colorG));
                        }
                    }
                }

                // 如果成功读取了点，计算缩放和偏移，并添加到points列表
                if (originalPoints.Count > 0)
                {
                    // 计算原始点的边界框
                    float minX = float.MaxValue, minY = float.MaxValue;
                    float maxX = float.MinValue, maxY = float.MinValue;

                    foreach (PointWithColor p in originalPoints)
                    {
                        minX = Math.Min(minX, p.X);
                        minY = Math.Min(minY, p.Y);
                        maxX = Math.Max(maxX, p.X);
                        maxY = Math.Max(maxY, p.Y);
                    }

                    // 计算缩放因子和偏移量，保留一定边距
                    float margin = 50; // 边距（像素）
                    float scaleX = (pictureBox.Width - 2 * margin) / (maxX - minX);
                    float scaleY = (pictureBox.Height - 2 * margin) / (maxY - minY);
                    float scale = Math.Min(scaleX, scaleY); // 使用较小的缩放因子以保持纵横比

                    // 计算居中偏移
                    float offsetX = margin + (pictureBox.Width - 2 * margin - scale * (maxX - minX)) / 2;
                    float offsetY = margin + (pictureBox.Height - 2 * margin - scale * (maxY - minY)) / 2;

                    // 转换坐标并添加到points列表
                    int boxSize = 1;
                    int[,] ex = new int[this.pictureBox.Width / boxSize, this.pictureBox.Height / boxSize];

                    foreach (PointWithColor p in originalPoints)
                    {
                        int x = (int)(offsetX + scale * (p.X - minX));
                        int y = (int)(offsetY + scale * (p.Y - minY));
                        ex[x / boxSize, y / boxSize]++;
                    }

                    for (var i = 0; i < this.pictureBox.Width / boxSize; i++)
                    {
                        for (var j = 0; j < this.pictureBox.Height / boxSize; j++)
                        {
                            if (ex[i, j] >= 1)
                                points.Add(new Point(i * boxSize, j * boxSize));
                        }
                    }

                    // 刷新显示
                    pictureBox.Refresh();

                    // 显示读取成功信息
                    MessageBox.Show($"成功读取了 {points.Count} 个点。", "读取成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("未能从文件中读取有效的点数据。", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取文件时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #region 刷新
        private void button1_Click(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }

        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }
        private void checkBoxShowRegNum_CheckedChanged(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }
        private void checkBox4_CheckedChanged_1(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }
        #endregion

        #region 导出线段
        private void 导出线段ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // 创建保存文件对话框
            using (SaveFileDialog saveFileDialog = new SaveFileDialog())
            {
                saveFileDialog.Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*";
                saveFileDialog.Title = "保存线段数据";

                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        // 用于存储要写入文件的内容
                        List<string> lines = new List<string>();

                        // 遍历每个线段
                        foreach (Polyline segment in simplifiedSegments)
                        {
                            // 存储当前线段的点
                            List<string> pointStrings = new List<string>();
                            foreach (PointF2G point in segment.Points)
                            {
                                pointStrings.Add($"{point.X} {point.Y}");
                            }
                            // 将当前线段的所有点用分号连接
                            lines.Add(string.Join(";", pointStrings));
                        }

                        // 将内容写入文件
                        System.IO.File.WriteAllLines(saveFileDialog.FileName, lines);
                        MessageBox.Show("线段数据保存成功。", "保存成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"保存文件时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
        private void 导入线段ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // 创建打开文件对话框
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*";
                openFileDialog.Title = "选择线段数据文件";

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        // 读取文件的所有行
                        string[] lines = System.IO.File.ReadAllLines(openFileDialog.FileName);
                        List<Polyline> importedSegments = new List<Polyline>();

                        // 遍历每一行
                        foreach (string line in lines)
                        {
                            // 按分号分割得到每个点的字符串
                            string[] pointStrings = line.Split(';');
                            List<PointF2G> segment = new List<PointF2G>();

                            // 遍历每个点的字符串
                            foreach (string pointStr in pointStrings)
                            {
                                // 按空格分割得到 X 和 Y 坐标
                                string[] parts = pointStr.Split(' ');
                                if (parts.Length >= 2 && float.TryParse(parts[0], out float x) && float.TryParse(parts[1], out float y))
                                {
                                    segment.Add(new PointF2G(x, y));
                                }
                            }

                            if (segment.Count > 0)
                            {
                                importedSegments.Add(new Polyline() { Points = segment });
                            }
                        }

                        // 合并导入的线段
                        simplifiedSegments.AddRange(importedSegments);
                        // 刷新显示
                        pictureBox.Refresh();
                        MessageBox.Show("线段数据导入成功。", "导入成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"读取文件时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
        #endregion

        private void 分析图片ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PngLine.RedImg();
        }

        
    }
}
